from microbit import *
import neopixel

n1 = neopixel.NeoPixel(pin8, 8)
n2 = neopixel.NeoPixel(pin12, 8)
n3 = neopixel.NeoPixel(pin14, 8)
n4 = neopixel.NeoPixel(pin16, 8)
n1.clear()
n2.clear()
n3.clear()
n4.clear()

class SP(object):
    def __init__(self):
        self.strips = {}
        self.strips['J1'] = n1
        self.strips['J2'] = n2
        self.strips['J3'] = n3
        self.strips['J4'] = n4
        self.brightness = { 'J1': 255.0, 'J2': 255.0, 'J3': 255.0, 'J4': 255.0}
        self.color = (0,0,0)

    def rotate(self, P = 'J1', offset = 1):
        offset = round(offset)
        if offset == 0:
            return
        strip = self.strips[P]
        nc = [(0,0,0)] * 8
        if offset > 0:
            for i in range(8 - 1, -1, -1):
                nc[(i + offset + 8) % 8] = strip[i]
        if offset < 0:
            for i in range(8 - 1, -1, -1):
                nc[(i + offset + 8) % 8] = strip[i]
        for i in range(0, 8):
            if nc[i]:
                strip[i] = nc[i]

    def offset(self, P = 'J1', offset = 1):
        strip = self.strips[P]
        offset = round(offset)
        if offset == 0:
            return
        if offset > 7:
            self.fill_empty()
            return
        if offset > 0:
            for index in range(7, -1, -1):
                if (index - offset) < 0:
                    strip[index] = (0,0,0)
                else:
                    strip[index] = strip[index - offset]
        if offset < 0:
            newColor = [(0,0,0)] * 8
            for index in range(8):
                if (index + offset) < 0:
                    newColor[index] = (0,0,0)
                else:
                    newColor[index + offset] = strip[index]
            for index in range(0, 8):
                strip[index] = newColor[index]

    def initStripColor(self, RJpIN, HueStart, HueEnd):
        strip = self.strips[RJpIN]
        diff = (HueEnd - HueStart) / 8
        for index in range(8):
            r,g,b = hue_to_rgb(HueStart + index * diff)
            br = self.brightness[RJpIN]/255
            r = int(r * br)
            g = int(g * br)
            b = int(b * br)
            strip[index] = (r,g,b)

    def show_rainbow(self, RJpIN, HueStart: float, HueEnd: float):
        HueStart = 0 if HueStart < 0 else HueStart
        HueEnd = 360 if HueStart > 360 else HueEnd
        self.initStripColor(RJpIN, HueStart, HueEnd)
        self.strips[RJpIN].show()

    def fill_color_hex(self, RJpIN = 'J1', color = "#FF0000"):
        self.color = hex_to_rgb(color)
        color = self.get_b_color(RJpIN)
        self.strips[RJpIN].fill(color)
        self.strips[RJpIN].show()

    def fill_color_hsv(self, RJpIN, h, s, v):
        color = colorStrToRGB('hsv(' + ",".join(str(item) for item in[h,s,v]) + ')')
        if not color:
            return
        self.strips[RJpIN].fill(color)
        self.strips[RJpIN].show()

    def fill_color_rgb(self, RJpIN, r, g, b):
        color = colorStrToRGB('rgb(' + ",".join(str(item) for item in[r,g,b]) + ')')
        if not color:
            return
        self.strips[RJpIN].fill(color)
        self.strips[RJpIN].show()

    def fill_empty(self, RJpIN = 'J1'):
        for index in range(8):
            self.strips[RJpIN][index] = (0,0,0)

    def get_b_color(self, RJpIN = 'J1'):
        (r,g,b) = self.color
        br = self.brightness[RJpIN]/255
        r = int(r * br)
        g = int(g * br)
        b = int(b * br)
        return (r,g,b)

    def set_color_hex(self, RJpIN, pos, color):
        pos = 0 if pos < 0 else pos
        pos = 7 if pos > 7 else pos
        color = colorStrToRGB(color)
        self.color = color
        c_color = self.get_b_color(RJpIN)
        self.strips[RJpIN][pos] = c_color
        self.strips[RJpIN].show()

    def set_color_hsv(self, RJpIN, pos, h, s, v):
        pos = 0 if pos < 0 else pos
        pos = 7 if pos >7 else pos
        color = colorStrToRGB('hsv(' + ",".join(str(item) for item in[h,s,v]) + ')')
        if not color:
            return
        self.color = hex_to_rgb(color)
        self.strips[RJpIN][pos] = self.get_b_color(RJpIN)
        self.strips[RJpIN].show()

    def set_color_rgb(self, RJpIN, pos, r, g, b):
        pos = 0 if pos < 0 else pos
        pos = 7 if pos >7 else pos
        self.color = hex_to_rgb((r, g, b))
        self.strips[RJpIN][pos] =  self.get_b_color(RJpIN)
        self.strips[RJpIN].show()

    def clear(self, RJpIN = 'J1'):
        self.color = (0, 0, 0)
        self.strips[RJpIN].clear()

    def set_brightness(self, RJPin = 'J1', brightness = 255.0):
        self.brightness[RJPin] = brightness
        for index in range(8):
            c = self.get_b_color(RJPin)
            self.strips[RJPin][index] = c
        self.show()

    def show(self,RJPin = 'J1'):
       self.strips[RJPin].show()

def hue_to_rgb(hue):
    hue = hue % 360
    h = hue / 60
    c = 1
    x = 1 - abs(h % 2 - 1)

    if h < 1:
        rgb = (c, x, 0)
    elif h < 2:
        rgb = (x, c, 0)
    elif h < 3:
        rgb = (0, c, x)
    elif h < 4:
        rgb = (0, x, c)
    elif h < 5:
        rgb = (x, 0, c)
    else:
        rgb = (c, 0, x)

    m = 1 - c
    r, g, b = rgb
    r = int((r + m) * 255)
    g = int((g + m) * 255)
    b = int((b + m) * 255)

    return r, g, b

def colorHSV(hue, sat = 128, val = 255):
        if hue >= 65536:
            hue %= 65536

        hue = (hue * 1530 + 32768) // 65536
        if hue < 510:
            b = 0
            if hue < 255:
                r = 255
                g = hue
            else:
                r = 510 - hue
                g = 255
        elif hue < 1020:
            r = 0
            if hue < 765:
                g = 255
                b = hue - 510
            else:
                g = 1020 - hue
                b = 255
        elif hue < 1530:
            g = 0
            if hue < 1275:
                r = hue - 1020
                b = 255
            else:
                r = 255
                b = 1530 - hue
        else:
            r = 255
            g = 0
            b = 0

        v1 = 1 + val
        s1 = 1 + sat
        s2 = 255 - sat

        r = ((((r * s1) >> 8) + s2) * v1) >> 8
        g = ((((g * s1) >> 8) + s2) * v1) >> 8
        b = ((((b * s1) >> 8) + s2) * v1) >> 8

        return r, g, b

def hex_to_rgb(hex_color):
    hex_color = hex_color.strip("#")
    r = int(hex_color[0:2], 16)
    g = int(hex_color[2:4], 16)
    b = int(hex_color[4:6], 16)
    return (r, g, b)

replacements = {
    "hsv": "",
    "rgb": "",
    "(": "",
    ")": ""
}

def trimColor(color):
    for old, new in replacements.items():
        color = color.replace(old, new)
    res = color.split(",")
    number_list = [int(x) for x in res]
    return tuple(number_list)

def hsv_to_rgb(h, s, v):
    if s == 0:
        r, g, b = v, v, v
    else:
        h *= 6
        i = int(h)
        f = h - i
        p = v * (1 - s)
        q = v * (1 - s * f)
        t = v * (1 - s * (1 - f))

        if i == 0:
            r, g, b = v, t, p
        elif i == 1:
            r, g, b = q, v, p
        elif i == 2:
            r, g, b = p, v, t
        elif i == 3:
            r, g, b = p, q, v
        elif i == 4:
            r, g, b = t, p, v
        else:
            r, g, b = v, p, q

    r_int = int(r * 255)
    g_int = int(g * 255)
    b_int = int(b * 255)

    return r_int, g_int, b_int

def colorStrToRGB(color):
    if color.startswith("#"):
        if not len(color) == 7:
            return None
        return hex_to_rgb(color)

    if color.startswith("hsv"):
        (h,s,v) = trimColor(color)
        h = 0 if h < 0 else h
        h = 360 if h > 360 else h
        s = 0 if s < 0 else s
        s = 100 if s > 100 else s
        v = 0 if v < 0 else v
        v = 100 if v > 100 else v
        return hsv_to_rgb(h/360,s/100,v/100)

    if color.startswith("rgb"):
        (r,g,b) = trimColor(color)
        r = 0 if r < 0 else r
        r = 255 if r > 255 else r
        g = 0 if g < 0 else g
        g = 255 if g > 255 else g
        b = 0 if b < 0 else b
        b = 255 if b > 255 else b
        return (r,g,b)
    return None

strip = SP()
